home *** CD-ROM | disk | FTP | other *** search
/ World of Education / World of Education.iso / world_x / xcoral16.zip / SCROLL.C < prev    next >
C/C++ Source or Header  |  1993-01-15  |  14KB  |  606 lines

  1. /*
  2. ** Copyright 1989, 1992 by Lionel Fournigault
  3. **
  4. ** Permission to use, copy, and distribute for non-commercial purposes,
  5. ** is hereby granted without fee, providing that the above copyright
  6. ** notice appear in all copies and that both the copyright notice and this
  7. ** permission notice appear in supporting documentation.
  8. ** The software may be modified for your own purposes, but modified versions
  9. ** may not be distributed.
  10. ** This software is provided "as is" without any expressed or implied warranty.
  11. **
  12. **
  13. */
  14.  
  15. #include <stdio.h>
  16. #include <X11/Xlib.h>
  17. #include <X11/cursorfont.h>
  18. #include <X11/Xutil.h>
  19. #include <malloc.h>
  20.  
  21. #include "scroll.h"
  22.  
  23. static char gray [] = { 0x1, 0x02 };
  24.  
  25. static Pixmap    pix;
  26. static Cursor   cursor;
  27. static int myrint ();
  28.  
  29. extern unsigned long PixelValue ();
  30. extern void Display3D ();
  31.  
  32. /*
  33. **    Function name : InitScroll
  34. **
  35. **    Description : Pour l'instant, on cree le cursor associe a
  36. **        la barre de scroll.
  37. **
  38. **    Input :  Le display.
  39. **    Ouput :
  40. */
  41. void InitScroll ( display )
  42.     Display    *display;
  43. {
  44.     pix = XCreatePixmapFromBitmapData ( display, 
  45.         DefaultRootWindow (display), gray, 2, 2, 
  46.         BlackPixel ( display, DefaultScreen (display)),
  47.         WhitePixel ( display, DefaultScreen (display)),
  48.         DefaultDepth (display, DefaultScreen ( display )));
  49.  
  50.     cursor = XCreateFontCursor ( display, XC_sb_left_arrow );
  51. }
  52.  
  53.  
  54. /*
  55. **    Function name : MakeScroll
  56. **
  57. **    Description :  Construction d'une fenetre de scroll avec la
  58. **        scrollbar.
  59. **
  60. **    Input :  Le display, la fenetre parent, position dans la fenetre
  61. **        parent.
  62. **    Ouput : Un pointeur sur SWin
  63. */
  64. SWin *MakeScroll ( display, parent, x, y )
  65.     Display    *display;
  66.     Window    parent;
  67.     register int x, y;
  68. {
  69.     SWin *s;
  70.     int result;
  71.     unsigned long pixel;
  72.     
  73.     s = (SWin *) malloc ( (unsigned) sizeof ( SWin )); 
  74.  
  75.     s -> frame = XCreateSimpleWindow ( display, parent,
  76.         x, y, SCROLL_WIDTH - 2, DEFAULT_SIZE, 0,
  77.         BlackPixel ( display, DefaultScreen (display)),
  78.         WhitePixel ( display, DefaultScreen (display)));
  79.  
  80.     XSelectInput ( display, s -> frame, ButtonPressMask | ButtonMotionMask
  81.         | ButtonReleaseMask | ExposureMask | PointerMotionHintMask );
  82.  
  83.     s -> fx = x; s -> fy = y;
  84.  
  85.     s -> scroll = XCreateSimpleWindow ( display, s -> frame,
  86.         2, 2, SCROLL_WIDTH - 4 , DEFAULT_SIZE, 0,
  87.         BlackPixel ( display, DefaultScreen (display)),
  88.         WhitePixel ( display, DefaultScreen (display)));
  89.  
  90.     s -> sx = 2; s -> sy = 2;
  91.     s -> line = s -> linepage = 0;
  92.     s -> line_to_scroll = 0;
  93.     s -> rest = 0;
  94.     s -> last_dir = 0;
  95.  
  96.     XSelectInput ( display, s -> scroll, ExposureMask );
  97.     s -> width = SCROLL_WIDTH;
  98.  
  99.     if ( DefaultDepth ( display, DefaultScreen (display)) == 1 ) {
  100.         /* Black and White */
  101.         XSetWindowBackgroundPixmap ( display, s -> scroll, pix );
  102.         s -> bg = BlackPixel ( display, DefaultScreen (display));
  103.         s -> fg = WhitePixel ( display, DefaultScreen (display));
  104.     }
  105.     else {
  106.         /* Color */
  107.         pixel = PixelValue ( display, "gray", &result );
  108.         if ( result == False )
  109.             pixel = BlackPixel ( display, DefaultScreen (display));
  110.         XSetWindowBackground ( display, s -> scroll, pixel );
  111.  
  112.         pixel = PixelValue ( display, "gray65", &result );
  113.         if ( result == False )
  114.             pixel = WhitePixel ( display, DefaultScreen (display));
  115.         XSetWindowBackground ( display, s -> frame, pixel );
  116.  
  117.         s -> bg = PixelValue ( display, "gainsboro", &result );
  118.         if ( result == False )
  119.             s -> bg = PixelValue ( display, "white", &result );
  120.         s -> fg = PixelValue ( display, "dimgray", &result );
  121.         if ( result == False )
  122.             s -> fg = PixelValue ( display, "black", &result );    
  123.     }
  124.     return ( s );
  125. }
  126.  
  127.  
  128. /*
  129. **    Function name : DeleteScroll
  130. **
  131. **    Description : Comme son nom l'indique.
  132. **
  133. **    Input : Le display, la fenetre de scroll
  134. **    Ouput :
  135. */
  136. void DeleteScroll ( display, swin )
  137. Display *display;
  138. SWin *swin;
  139. {
  140.     XDestroyWindow ( display, swin -> frame );
  141.     (void) free ( (char *) swin );
  142. }
  143.  
  144.  
  145. /*
  146. **    Function name : SetScrollLine
  147. **
  148. **    Description :  Positionne le nombre de ligne a scroller
  149. **
  150. **    Input :  Le display, nb lignes.
  151. **    Ouput :
  152. */
  153. void SetScrollLine ( s, n )
  154.     SWin *s;
  155.     register int n;
  156. {
  157.     s -> line = n;
  158.     s -> line_to_scroll = n - 1;
  159.  
  160. #ifdef DEBUG
  161.     (void) fprintf ( stderr, "lines in buf = %d\n", s -> line );
  162. #endif
  163. }
  164.  
  165.  
  166. /*
  167. **    Function name : RefreshScroll
  168. **
  169. **    Description :  Ajuste la geometrie de la fenetre de scroll.
  170. **        Positionne la scrollbar au bon endroit. Cette fonction
  171. **        est utilisee apres un resize de la fenetre parent.
  172. **
  173. **    Input : Le display, le scroll, largeur, hauteur, no de la ligne courante.
  174. **    Ouput :
  175. */
  176. void RefreshScroll ( display, swin, width, height, n )
  177.     Display *display;
  178.     SWin    *swin;
  179.     int     width, height, n;
  180. {
  181.     swin -> f_height = height;
  182.     swin -> fx = width - SCROLL_WIDTH;
  183.     ShowScrollFrame ( display, swin );
  184.      (void) MoveScrollBar ( display, swin, CURRENT, n );
  185. }
  186.  
  187.  
  188. /*
  189. **    Function name : ShowScrollFrame
  190. **
  191. **    Description :  Affiche la fenetre de scroll en fonction de la
  192. **        geometrie courante. Positionne la taille de la scrollbar.
  193. **
  194. **    Input :  Les display, le scroll
  195. **    Ouput :
  196. */
  197. void ShowScrollFrame ( display, swin )
  198.     Display *display;
  199.     SWin *swin;
  200. {
  201.     XMoveResizeWindow ( display, 
  202.         swin -> frame,
  203.         swin -> fx,
  204.         swin -> fy,
  205.         swin -> width,
  206.         swin -> f_height );
  207.  
  208.     XMapWindow ( display, swin -> frame );
  209.     SetScrollBarSize ( display, swin );
  210. }
  211.  
  212.  
  213. /*
  214. **    Function name : SetScrollBarSize
  215. **
  216. **    Description :  Calcul de la taille de la scrollbar.
  217. **
  218. **    Input : Le display, le scroll.
  219. **    Ouput :
  220. */
  221. void SetScrollBarSize ( display, swin )
  222.     Display *display;
  223.     SWin *swin;
  224. {
  225.     double x;
  226.  
  227.     x = ((double) swin -> linepage) 
  228.         / ((double) swin -> line_to_scroll + swin -> linepage);
  229.  
  230.     if ( swin -> line == 0 )
  231.         swin -> s_height = swin -> f_height - 4;
  232.  
  233.     swin -> s_height = (int)( myrint ((float)(swin -> f_height - 4 ) * x));
  234.  
  235.     if ( swin -> s_height < 10 ) {
  236. #ifdef DEBUG
  237.         (void) fprintf ( stderr, "s_height 10\n" );
  238. #endif DEBUG
  239.         swin -> s_height = 10;
  240.     }
  241.     XResizeWindow ( display, swin -> scroll, SCROLL_WIDTH - 4, swin -> s_height ); 
  242.  
  243.     XMapWindow ( display, swin -> scroll );
  244.  
  245.     if ( swin -> line_to_scroll != 0 )
  246.         swin -> delta = ((double)( swin -> f_height - 4 - swin -> s_height ) 
  247.             / (double)(swin -> line_to_scroll));
  248.     else
  249.         swin -> delta = 0;    
  250. #ifdef DEBUG
  251.     (void) fprintf ( stderr, "delta = %.2f n = %.2f\n", 
  252.          swin -> delta, ( swin -> f_height - 4 - swin -> s_height ) / swin -> delta );
  253. #endif DEBUG
  254. }
  255.  
  256.  
  257. /*
  258. **    Function name : ExposeInScroll
  259. **
  260. **    Description : Traitement d'un expose event.
  261. **    Input : Le display, la fenetre exposee, le scroll courant.
  262. **    Ouput : Vrai si le courant est expose faux sinon.
  263. */
  264. int ExposeInScroll ( dpy, w, swin )
  265.     Display *dpy;
  266.     Window w;
  267.     SWin *swin;
  268. {
  269.        XEvent ev;
  270.     
  271.        if ( w == swin -> frame ) {    
  272.         RefreshScrollFrame ( dpy, swin );
  273.         while ( XCheckWindowEvent ( dpy, w,ExposureMask, &ev ));
  274.         return True;
  275.     }
  276.     if ( w == swin -> scroll ) {
  277.         RefreshScrollBar ( dpy, swin );
  278.         while ( XCheckWindowEvent ( dpy, w, ExposureMask, &ev ));
  279.         return True;
  280.     }
  281.     return False;
  282. }
  283.  
  284. /*
  285. **    Function name : ButtonPressInScroll
  286. **
  287. **    Description :  Comme son nom l'indique.
  288. **
  289. **    Input : le scroll, le fenetre qui a recu ButtonPress, y position.
  290. **    Ouput : True or False.
  291. */
  292. int ButtonPressInScroll ( swin, w, y, result )
  293.     SWin *swin;
  294.     Window w;
  295.     register int y;
  296.     register int *result;    /* RETURN */
  297. {
  298.     if ( swin -> frame != w )
  299.         return False;
  300.  
  301.     if ( y < swin -> sy ) 
  302.         *result = PREVIOUS;
  303.     else if ( y > swin -> s_height + swin -> sy ) 
  304.         *result = NEXT;
  305.     else {
  306.         swin -> y_max = swin -> f_height - 2 - ( swin -> sy + swin -> s_height - y );
  307.         swin -> y_min = y - swin -> sy + 2;
  308.         swin -> last_y = y;
  309. #ifdef DEBUG
  310.         (void) fprintf ( stderr, "y_max = %d y_min = %d\n",
  311.             swin -> y_max, swin -> y_min );
  312. #endif DEBUG
  313.         *result = CURSOR;
  314.     }
  315.     return True;
  316. }
  317.  
  318.  
  319. /*
  320. **    Function name : HandleScrollBar
  321. **
  322. **    Description :  Synchronise la scrollbar avec le defilement du texte pendant
  323. **        le ButtonPress.
  324. **        Pas simple mes amis, pas simple. 
  325. **
  326. **    Input :  Le display, le scroll, la callback.
  327. **    Ouput :
  328. */
  329. void HandleScrollBar ( display, swin, f )
  330.     Display *display;
  331.     SWin *swin;
  332.     void (*f) ();
  333. {
  334.     register int n, dy;
  335.     double dn = 0;
  336.     XEvent event;
  337.     Window root, child;
  338.     unsigned int keys_buttons;
  339.     int root_x, root_y, win_x, win_y, stat = NULL;
  340.        
  341.     while ( XCheckMaskEvent ( display, PointerMotionMask, &event ));
  342.     XDefineCursor ( display, swin -> frame, cursor );
  343.  
  344. /*    XGrabPointer ( display, swin -> frame, True, ButtonReleaseMask, */
  345.     XGrabPointer ( display, swin -> frame, True, ButtonReleaseMask | PointerMotionMask,
  346.         GrabModeAsync, GrabModeAsync, swin -> frame, None, CurrentTime );
  347.  
  348. #ifdef DEBUG
  349.     fprintf ( stderr, "delta = %.3f f_height = %d s_height = %d\n",
  350.         swin -> delta, swin -> f_height, swin -> s_height );
  351. #endif
  352.     dn = swin -> rest;
  353.     for ( ;; ) {
  354.         XNextEvent ( display, &event );
  355.         switch ( event.type ) {
  356.         case ButtonRelease:
  357.             XUngrabPointer ( display, CurrentTime );
  358.             XUndefineCursor ( display, swin -> frame );
  359.             swin -> last_y = 0;
  360.             swin -> rest = dn;
  361. #ifdef DEBUG
  362.     fprintf ( stderr, "dn = %.2f rest = %.2f i = %d\n", dn, swin -> rest, i );
  363. #endif
  364.             return;
  365.         case MotionNotify:
  366.             while ( XCheckMaskEvent ( display,
  367.                 ButtonMotionMask, &event ));
  368.             XQueryPointer ( display,
  369.                 event.xmotion.window, &root, &child, &root_x,
  370.                 &root_y, &win_x, &win_y, &keys_buttons );
  371.             if ( (dy = win_y - swin -> last_y ) == NULL ) continue;
  372.             if ( dy > NULL ) {
  373.                 if ( stat != BOTTOM ) {
  374.                     if ( (stat = MoveScrollBar ( display,
  375.                        swin, DOWN, win_y - swin -> last_y )) == BOTTOM ) {
  376.                         win_y = swin -> y_max;
  377.                         swin -> rest = 0;
  378.                         dy = win_y - swin -> last_y;
  379.                     }
  380.                     dn += (dy / swin -> delta);
  381.                     n = (int) (myrint ((float)dn));  
  382.                     if ( n > NULL ) {
  383.                         swin -> rest = (double) (dn - n);
  384.                         ( * f ) ( n, swin -> text );
  385.                         dn = swin -> rest;
  386.                     }
  387.                     swin -> last_dir = BOTTOM;
  388.                     swin -> last_y = win_y;
  389.                 }
  390.                 else 
  391.                              continue;
  392.             }
  393.             else {
  394.                 if ( stat != TOP ) {
  395.                     if ( (stat = MoveScrollBar ( display,
  396.                        swin, UP, swin -> last_y - win_y )) == TOP ) {
  397.                         win_y = swin -> y_min;
  398.                         swin -> rest = 0;
  399.                         dy = win_y - swin -> last_y;
  400.                     }
  401.                     dn += dy / swin -> delta;
  402.                     n = (int) (myrint ((float)dn));
  403.                     if ( n < NULL ) {
  404.                         swin -> rest = (double) (dn - n);
  405.                         ( * f ) ( n, swin -> text );
  406.                         dn = swin -> rest;
  407.                     }
  408.                     swin  -> last_dir = TOP;
  409.                     swin -> last_y = win_y;
  410.                 }
  411.                 else
  412.                     continue;
  413.             }
  414. #ifdef DEBUG
  415.     (void) fprintf ( stderr, "dy = %d\tlast = %d\n", dy, swin -> last_y );
  416. #endif
  417.  
  418. #ifdef DEBUG
  419.     (void) fprintf ( stderr, "dy = %d\tdn = %.2f\tn = %d\t rest = %.2f\n",
  420.         dy, dn , n, swin -> rest );
  421. #endif
  422.             break;
  423.         }
  424.     }
  425. }
  426.  
  427.  
  428. /*
  429. **    Function name : MoveScrollBar
  430. **
  431. **    Description :  Deplacement de la scrollbar suivant la valeur du
  432. **        flag ( 1er page, page suivante... etc ).
  433. **
  434. **    Input :  Le display, le scroll, flags, deplacement en pixels
  435. **    Ouput : L'etat courant.
  436. */
  437. int MoveScrollBar ( display, swin, flag, dy )
  438.     Display *display;
  439.     SWin *swin;
  440.     register int dy;
  441. {
  442.     register int stat = NULL;
  443.     register int i=0, j=0, n=0;
  444.     double dn = swin -> rest;
  445. #ifdef DEBUG
  446.     fprintf ( stderr, "dy = %d\n", dy );
  447. #endif
  448.     if ( swin -> sy == 2 ) {
  449.         stat = TOP;
  450.         swin -> rest = 0;
  451.     }
  452.     if ( swin -> sy == swin -> f_height - 2 - swin -> s_height ) {
  453.         stat = BOTTOM;
  454.         swin -> rest = 0;
  455.     }
  456.     switch ( flag ) {
  457.     case UP:
  458.         if ( stat == TOP )
  459.             return stat;
  460.         if ( swin -> sy - dy < 2 ) {
  461.             swin -> sy = 2;
  462.             stat = TOP;
  463.         }
  464.         else {
  465.             swin -> sy -= dy;
  466.             stat = OTHER;
  467.         }
  468.         break;
  469.     case DOWN:
  470.         if ( stat == BOTTOM )
  471.             return stat;
  472.         if ( (swin -> sy + dy) > (swin -> f_height -2 - swin -> s_height)) {
  473.             swin -> sy = swin -> f_height - 2 - swin -> s_height;
  474.             stat = BOTTOM;
  475.         }
  476.         else {
  477.             swin -> sy += dy;
  478.             stat = OTHER;
  479.         }
  480.         break;
  481.     case FIRST:
  482.         swin -> sy = 2;
  483.         swin -> rest = 0;
  484.         stat = TOP;
  485.         break;
  486.     case NEXT:
  487.         j = swin -> linepage - 1;
  488.         while ( n < j ) {
  489.             i++;
  490.             dn += ( 1 / swin -> delta);
  491.             n = (int) (myrint ((float)dn));
  492.         }
  493.         swin -> sy += i;
  494.         swin -> rest = (double) (dn - j);
  495. #ifdef DEBUG
  496.     (void) fprintf ( stderr, "i = %d rest = %.3f dn = %.3f n = %d \n",
  497.         i, swin -> rest, dn, n );
  498. #endif DEBUG
  499.         if ( swin -> sy > (swin -> f_height -2 - swin -> s_height) ) {
  500.             swin -> sy = swin -> f_height - 2 - swin -> s_height;
  501.             stat = BOTTOM;
  502.             swin -> rest = 0;
  503.         }
  504.         stat = OTHER;
  505.         break;
  506.     case PREVIOUS:
  507.         j = swin -> linepage - 1;
  508.         while ( -n < j ) {
  509.             i ++;
  510.             dn += ( (-1) / swin -> delta );
  511.             n = (int) myrint ((float)dn);
  512.         }
  513.         swin -> sy -= i;
  514.         swin -> rest = (double) (dn - (-j));
  515. #ifdef DEBUG
  516.     (void) fprintf ( stderr, "i = %d rest = %.3f dn = %.3f n = %d \n",
  517.         i, swin -> rest, dn, n );
  518. #endif DEBUG
  519.         if ( swin -> sy < 2 ) {
  520.             swin -> sy = 2;
  521.             stat = TOP;
  522.             swin -> rest = 0;
  523.         }
  524.         stat = OTHER;
  525.         break;
  526.     case CURRENT:
  527.         /* Le nombre de lignes qu'il aurait fallu scroller a partir du debut.  */
  528.         j = dy;
  529.         dn = 0;
  530. #ifdef DEBUG
  531.     (void) fprintf ( stderr,"j = %d\n", j );
  532. #endif
  533.         if ( dy == 0 )
  534.             return 0;
  535.         while ( n < j ) {
  536.             i++;
  537.             dn += ( 1 / swin -> delta);
  538.             n = (int) (myrint ((float)dn));
  539.         }
  540.         swin -> sy = i + 2;
  541.         if ( swin -> sy < 2 ) swin -> sy = 2;
  542.         swin -> rest = (double) (dn - j);
  543.         break;
  544.     }       
  545.     XMoveWindow ( display, swin -> scroll, swin -> sx, swin -> sy );
  546.     XFlush ( display );
  547.     return stat;
  548. }
  549.  
  550.  
  551. /*
  552. **    Function name : RefreshScrollBar
  553. **
  554. **    Description :  Affichage du 3D pour la scrollbar.
  555. **
  556. **    Input : Le display, le scroll
  557. **    Ouput :
  558. */
  559. void RefreshScrollBar ( display, s )
  560.     Display *display;
  561.     SWin *s;
  562. {
  563.     Display3D ( display, s -> scroll, s -> bg , s -> fg , 2, UP );
  564. }
  565.  
  566. /*
  567. **    Function name : RefreshScrollFrame
  568. **
  569. **    Description :  Affichage du 3D pour la fenetre de scroll.
  570. **
  571. **    Input : Le display, le scroll
  572. **    Ouput :
  573. */
  574. void RefreshScrollFrame ( display, s )
  575.     Display *display;
  576.     SWin *s;
  577. {
  578.     Display3D ( display, s -> frame, s -> bg , s -> fg , 2, DOWN );
  579. }
  580.  
  581. /*
  582. **    Function name : myrint
  583. **
  584. **    Description :  Calcul de partie entiere. 
  585. **
  586. **    Input :  un reel signe
  587. **    Ouput : sa partie entiere
  588. */
  589. static int myrint ( x )
  590.     float x;
  591. {
  592.     register int i = (int) x;
  593.     register sign = (x >= 0) ? 1 : -1;
  594.     register float tmp = ( x - i ) ? ( x -i ) : - ( x - i );
  595.  
  596.     if ( (0x1 & i ) == 1 ) {
  597.         /* Impair */
  598.         if ( tmp >= .5 ) i += sign;
  599.     }
  600.     else {
  601.         /* Pair */
  602.         if ( tmp > .5 ) i += sign;
  603.     }
  604.     return i;
  605. }
  606.